Skip to content

feat: migrate video shorts to learning resources API#3361

Open
daniellefrappier18 wants to merge 8 commits into
mainfrom
daniellef/11036-video-shorts-learning-resources-api
Open

feat: migrate video shorts to learning resources API#3361
daniellefrappier18 wants to merge 8 commits into
mainfrom
daniellef/11036-video-shorts-learning-resources-api

Conversation

@daniellefrappier18
Copy link
Copy Markdown
Contributor

@daniellefrappier18 daniellefrappier18 commented May 20, 2026

What are the relevant tickets?

Closes https://github.com/mitodl/hq/issues/11036

Description (What does it do?)

This branch migrates Video Shorts from the old v0 API shape to the v1 learning-resources API shape. The modal now uses VideoResource and plays video.streaming_url instead of the old direct MP4 URL.

Screenshots (if appropriate):

  • Desktop screenshots
  • Mobile width screenshots
new-video-shorts.mov

How can this be tested?

Automated tests

  • Run the updated unit tests to verify the component renders correctly with the new VideoResource shape

Manual testing

  1. Navigate to the homepage and confirm the Video Shorts carousel section loads. Thumbnail images should appear.
  2. Click a thumbnail to open the modal. The video should begin playing automatically (muted).
  3. Scroll/swipe through multiple shorts in the modal and verify each video loads and plays from the HLS streaming_url.
  4. Toggle the mute/unmute button and confirm audio state changes correctly.
  5. Verify the modal closes cleanly via the close button.
  6. Confirm thumbnail images display correctly (sourced from video.image.url instead of the old thumbnail_small_url).
  7. Resize to mobile width (< 900px) and verify the carousel and modal render at full width without layout issues.

Additional Context

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

OpenAPI Changes

No changes detected

View full changelog

Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

@daniellefrappier18 daniellefrappier18 marked this pull request as ready for review May 20, 2026 17:18
Copilot AI review requested due to automatic review settings May 20, 2026 17:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the Home Page “Video Shorts” feature from the legacy v0 VideoShort API shape to the v1 Learning Resources VideoResource shape, including switching playback to video.streaming_url.

Changes:

  • Replace v0 useVideoShortsList usage in the Home Page section with a v1 Learning Resources search-based hook.
  • Update the Video Shorts modal to consume VideoResource and play video.video.streaming_url with revised portrait sizing.
  • Update modal tests to use v1 factories/types and validate streaming_url handling.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
frontends/main/src/app-pages/HomePage/VideoShortsSection.tsx Swaps data source to v1 VideoResource list and updates thumbnail rendering + keys.
frontends/main/src/app-pages/HomePage/VideoShortsModal.tsx Switches modal playback to streaming_url and adjusts slide sizing/styling.
frontends/main/src/app-pages/HomePage/VideoShortsModal.test.tsx Updates tests to v1 VideoResource factories and adjusts assertions for new fields.
frontends/api/src/hooks/videoShorts/index.ts Adds a new hook that fetches Video Shorts via Learning Resources search and filters to videos.
Comments suppressed due to low confidence (1)

frontends/main/src/app-pages/HomePage/VideoShortsModal.tsx:189

  • video.video.streaming_url is documented/produced as an HLS .m3u8 URL (see backend help_text/tests). A plain <video src="...m3u8"> will not play on many browsers (notably Chrome/Firefox) without an HLS-capable player (e.g., video.js/hls.js) or a non-HLS fallback. Consider reusing the existing VideoJsPlayer/VideoResourcePlayer + resolveVideoSources pattern used elsewhere in main so HLS works cross-browser, rather than relying on native <video>.
    <Video
      ref={refCallback}
      onClick={onVideoClick}
      src={src}
      autoPlay
      muted
      playsInline
      webkit-playsinline="true"
      controlsList="nofullscreen"
      disablePictureInPicture

Comment thread frontends/main/src/app-pages/HomePage/VideoShortsModal.tsx Outdated
Comment thread frontends/main/src/app-pages/HomePage/VideoShortsModal.tsx Outdated
Comment thread frontends/main/src/app-pages/HomePage/VideoShortsSection.tsx
daniellefrappier18 and others added 2 commits May 20, 2026 13:32
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

frontends/main/src/app-pages/HomePage/VideoShortsModal.tsx:196

  • video.video?.streaming_url will often be an HLS .m3u8 (per existing VideoResource playback paths). Rendering it directly in a native <video src=...> will fail to play on browsers without native HLS support (e.g., Chrome/Firefox). Consider reusing the existing VideoJsPlayer/VideoResourcePlayer + resolveVideoSources approach (or an HLS polyfill) so Video Shorts are playable cross-browser.
    <Video
      ref={refCallback}
      onClick={onVideoClick}
      src={src}
      autoPlay
      muted
      playsInline
      webkit-playsinline="true"
      controlsList="nofullscreen"
      disablePictureInPicture
      width={videoWidth}
      height={videoHeight}
      preload="metadata"
      loop
    />

Comment thread frontends/main/src/app-pages/HomePage/VideoShortsModal.tsx
Comment thread frontends/api/src/hooks/videoShorts/index.ts Outdated
@daniellefrappier18 daniellefrappier18 added the Needs Review An open Pull Request that is ready for review label May 21, 2026
@daniellefrappier18
Copy link
Copy Markdown
Contributor Author

daniellefrappier18 commented May 21, 2026

For a solution to the videos appearing "soft" for a brief moment on startup due to adaptive HLS rendition selection @mbertrand has created the following issue.

Matt implemented ^ and this has solved the issue.

Copy link
Copy Markdown
Contributor

@ChristopherChudzicki ChristopherChudzicki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.. One request!

I did not notice any degradation of quality in first few moments. Maybe that's @mbertrand 's recent change.


const VideoShortsSection = () => {
const { data, isLoading } = useVideoShortsList()
const { data, isLoading } = useVideoShortsLearningResources()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is long-winded, it boils down to a few things:

  1. use the existing learningResourceQueries.search query
    • After this, I expect you could remove the whole api/hooks/video_shorts directory
  2. I think we should add sortby: "new"
    • The default search is pretty similar when there's no q filter (search query text), but IMO best to explicitly use new, that's closest to old -published_at, I think.

Rather than adding a new hook useVideoShortsLearningResources, I'd suggest re-using the existing learningResourceQueries.search query. Something like below.

Also:

  • filter on resource_type at the API level rather than afterwards. (It probably doesn't matter much since you were filtering on "Video Short" category anyway)
    • Generally filtering serverside is better...if you request 50 results and filter client-side, you might end up with fewer. But, as I said, it shouldn't matter here. Still good to do.

I'd suggest using

  const { data, isLoading } = useQuery({
    ...learningResourceQueries.search({
      resource_category: ["Video Short"],
      resource_type: [ResourceTypeEnum.Video],
      limit: 50,
      sortBy: "new"
    }),
    select: (data) =>
      data?.result.results.filter(
        (r) => r.resource_type === ResourceTypeEnum.Video,
      ),
  })

Two notes about the select i suggested:

  1. This query returns { results, time } after Search response time indicator for admin users #3186 ... it's the only query that does this, for the reasons mentioned in that pr.
  2. The filter inside select is redundant. I kept it just to make TS happy.

Also

  • generally nowadays we prefer useQuery(queryOptions) rather than defining custom query hooks.
  • In older versions of @tanstack/react-query, defining custom query hooks was the best way, but the queryOptions helper they added in v5 eliminated the need for custom query hooks. (Custom mutation hooks still big helpful.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I followed the pattern from the existing useVideoShortsList hook when writing useVideoShortsLearningResources, but I can see now that using useQuery(queryOptions) is the cleaner approach. I'll keep that in mind going forward.

@ChristopherChudzicki ChristopherChudzicki added Waiting on author and removed Needs Review An open Pull Request that is ready for review labels May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants